﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SymWorld.Model
{
    public class ParticleState
    {
        private ParticleKind _particleKind;
        private Vector _position;
        private Vector _velocity;
        private WorldState _worldState;

        public ParticleState(WorldState worldState, ParticleKind particleKind, Vector position, Vector velocity)
        {
            _worldState = worldState;
            _particleKind = particleKind;
            _position = position;
            _velocity = velocity;
        }

        public Vector Position
        {
            get { return _position; }
            set { _position = value; }
        }
        public Vector Velocity
        {
            get { return _velocity; }
            set { _velocity = value; }
        }
        public ParticleKind ParticleKind
        {
            get { return _particleKind; }
            set { _particleKind = value; }
        }
        public WorldState WorldState
        {
            get { return _worldState; }
        }

        public ParticleState GetPrevParticleState()
        {
            WorldState prevWorldState = _worldState.PrevWorldState;
            if (prevWorldState == null)
                return null;

            return prevWorldState.ParticleStateList[_worldState.ParticleStateList.IndexOf(this)];
        }
        public ParticleState CreateNextParticleState(WorldState nextWorldState, double delay)
        {
            return this.CreateNextParticleStateRelative(nextWorldState, delay);
        }
        public ParticleState CreateNextParticleStateSimple(WorldState nextWorldState, double delay)
        {
            // count force
            Vector force = new Vector();
            // net force is sum of all forces from all other particles
            foreach (ParticleState particleState in _worldState.ParticleStateList)
                if (particleState != this)
                {
                    // count force for other particle

                    ParticleState forcingOtherParticleState = particleState;
                    double timeDifference = 0d;
                    double forcingDistance;

                    // count time-space distance between particles
                    WorldState forcingWorldState = _worldState;
                    while (timeDifference < (forcingDistance = VectorExtension.Distance(forcingOtherParticleState.Position, this.Position)))
                    {
                        timeDifference += forcingWorldState.Delay;

                        ParticleState otherParticleHistoricState = forcingOtherParticleState.GetPrevParticleState();
                        WorldState historicWorldState = forcingWorldState.PrevWorldState;

                        if (historicWorldState == null || otherParticleHistoricState == null)
                            break;

                        forcingOtherParticleState = otherParticleHistoricState;
                        forcingWorldState = historicWorldState;
                    }

                    // check if age of the universe and distance allows force to appear
                    if (forcingOtherParticleState != null && timeDifference > forcingDistance)
                    {
                        // count force direction
                        Vector forceDirection = VectorExtension.Normalized(VectorExtension.Difference(this.Position, forcingOtherParticleState.Position));

                        // count force value for this other particle
                        double forceValue =
                            this.ParticleKind.ElectricCharge * forcingOtherParticleState.ParticleKind.ElectricCharge
                            /
                            timeDifference / timeDifference;

                        // add countet force to net force
                        force = VectorExtension.Sum(force, VectorExtension.Multiply(forceDirection, forceValue));
                    }
                }

            // count acceleration
            Vector acceleration = VectorExtension.Multiply(force, 1 / this.ParticleKind.Mass);

            // count velocity
            //Vector velocity = VectorExtension.Sum(this.Velocity, VectorExtension.Multiply(acceleration, delay)); // simple speed
            Vector velocity = VectorExtension.Sum(this.Velocity, VectorExtension.Multiply(acceleration, delay)); // relative speed

            // count position
            Vector position = VectorExtension.Sum(this.Position, VectorExtension.Multiply(velocity, delay));

            // construct new ParticleState object with results
            ParticleState retNextParticleState;
            retNextParticleState = new ParticleState(nextWorldState, this.ParticleKind, position, velocity);

            return retNextParticleState;
        }
    }
}
